package com.goldman.oss.common.platform.impl;

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.S3Object;
import com.goldman.oss.common.internal.pojo.*;
import com.goldman.oss.common.platform.FileStorage;
import com.goldman.oss.common.utils.PathUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.BeanUtils;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import java.util.function.Consumer;

/**
 * AWS S3 存储
 *
 * @author fdr
 */
@Data
@Slf4j
public class AwsS3FileStorage implements FileStorage {
    private String businessCode;
    private String accessKey;
    private String secretKey;
    private String region;
    private String endPoint;
    private String bucketName;
    private String domain;
    private String basePath;
    private volatile AmazonS3 client;

    private Long defaultExpirationInSeconds;

    public AmazonS3 getClient() {
        if (client == null) {
            synchronized (this) {
                if (client == null) {
                    AmazonS3ClientBuilder builder = AmazonS3ClientBuilder.standard()
                            .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKey, secretKey)));
                    if (StringUtils.isNotBlank(endPoint)) {

                        builder.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endPoint, region));
                    } else if (StringUtils.isNotBlank(region)) {
                        builder.withRegion(region);
                    }
                    client = builder.build();
                }
            }
        }
        return client;
    }

    @Override
    public void close() {
        if (client != null) {
            client.shutdown();
            client = null;
        }
    }

    @Override
    public UploadFileInfo store(MultipartFileWrapper fileWrapper) {
        try {
            return store(fileWrapper, fileWrapper.getMultipartFile().getInputStream());
        } catch (IOException e) {
            log.error("上传文件到obs异常：" + e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }

    @Override
    public UploadFileInfo store(CommonFileWrapper commonFileWrapper) {
        try {
            return store(commonFileWrapper, new FileInputStream(commonFileWrapper.getFile()));
        } catch (FileNotFoundException e) {
            log.error("上传文件到obs异常：" + e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }

    private UploadFileInfo store(FileWrapper fileWrapper, InputStream in) {
        log.info("开始上传文件到s3:{}", fileWrapper.getFilename());
        try {
            String objectKey = getObjectKey(fileWrapper);
            UploadFileInfo uploadFileInfo = new UploadFileInfo();
            BeanUtils.copyProperties(fileWrapper, uploadFileInfo);
            uploadFileInfo.setBasePath(basePath);
            uploadFileInfo.setObjectKey(objectKey);
            uploadFileInfo.setUrl(PathUtils.addFileSeparatorIfNot(domain) + objectKey);
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentLength(fileWrapper.getSize());
            getClient().putObject(bucketName, objectKey, in, metadata);
            return uploadFileInfo;
        } catch (Exception e) {
            log.error("上传文件到s3异常：" + e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }

    private String getObjectKey(FileWrapper fileWrapper) {
        String objectKey = PathUtils.addFileSeparatorIfNot(basePath) +
                PathUtils.addFileSeparatorIfNot(fileWrapper.getPath()) +
                fileWrapper.getFilename();
        return PathUtils.removeFirstFileSeparatorIfExists(objectKey);
    }


    @Override
    public String generateTemporaryUrl(DownloadFileInfo downloadFileInfo) {
        log.info("开始从s3获取临时URL:{}", downloadFileInfo.getObjectKey());
        try {
            String objectKey = downloadFileInfo.getObjectKey();
            GeneratePresignedUrlRequest urlRequest = new GeneratePresignedUrlRequest(bucketName, objectKey);
            Long expireInSeconds = downloadFileInfo.getExpirationTimeInSeconds() != null ?
                    downloadFileInfo.getExpirationTimeInSeconds() : defaultExpirationInSeconds;
            Date expirationDate = DateUtils.addSeconds(new Date(), Integer.parseInt(expireInSeconds + ""));
            urlRequest.setExpiration(expirationDate);
            URL url = getClient().generatePresignedUrl(urlRequest);
            return url.toString();
        } catch (Exception e) {
            log.error("获取url错误", e);
            throw new RuntimeException(e);
        }

    }

    @Override
    public String generatePublicUrl(String objectKey) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void download(DownloadFileInfo downloadFileInfo, Consumer<InputStream> consumer) {
        S3Object object = getClient().getObject(bucketName, downloadFileInfo.getObjectKey());
        try (InputStream in = object.getObjectContent()) {
            consumer.accept(in);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public InputStream download(DownloadFileInfo downloadFileInfo) {
        S3Object object = getClient().getObject(bucketName, downloadFileInfo.getObjectKey());
        return object.getObjectContent();
    }
}
